﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Effects;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;

namespace CameraControllers
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		private OrbitalCameraController m_CameraController;

		public MainWindow()
		{
			InitializeComponent();

			SetWindowTitle();

			m_CameraController = new OrbitalCameraController(new Vector3D(5.0, 3.0, 5.0));
			mainViewport.Camera = m_CameraController.Camera;
		}

		private void SetWindowTitle()
		{
			int up = (RenderCapability.Tier >> 16);
			int dn = (RenderCapability.Tier & 0xFFFF);
			this.Title = string.Format("Orbital Camera Controller - Tier: {0}-{1}", up, dn);
		}

		private void OnCreateTriangleButtonClick(object sender, RoutedEventArgs e)
		{
			Point3D point0 = new Point3D(0.0, 0.0, 0.0);
			Point3D point1 = new Point3D(5.0, 0.0, 0.0);
			Point3D point2 = new Point3D(0.0, 0.0, 5.0);

			Material material = new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(255, 0, 119, 170)));

			Model3DGroup triangle = CreateTriangle(point0, point2, point1, material);

			ModelVisual3D model = new ModelVisual3D();
			model.Content = triangle;

			Visual3D current = this.mainViewport.Children[0];
			this.mainViewport.Children.Clear();
			this.mainViewport.Children.Add(current);
			this.mainViewport.Children.Add(model);
		}

		private void OnCreateCubeButtomClick(object sender, RoutedEventArgs e)
		{
			Model3DGroup cube = new Model3DGroup();

			Point3D p0 = new Point3D(-1.0, -1.0, -1.0);
			Point3D p1 = new Point3D(1.0, -1.0, -1.0);
			Point3D p2 = new Point3D(1.0, -1.0, 1.0);
			Point3D p3 = new Point3D(-1.0, -1.0, 1.0);
			Point3D p4 = new Point3D(-1.0, 1.0, -1.0);
			Point3D p5 = new Point3D(1.0, 1.0, -1.0);
			Point3D p6 = new Point3D( 1.0, 1.0, 1.0);
			Point3D p7 = new Point3D(-1.0, 1.0, 1.0);

			Material material = new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(255, 0, 119, 170)));

			//front side triangles
			cube.Children.Add(CreateTriangle(p3, p2, p6, material));
			cube.Children.Add(CreateTriangle(p3, p6, p7, material));

			//right side triangles
			cube.Children.Add(CreateTriangle(p2, p1, p5, material));
			cube.Children.Add(CreateTriangle(p2, p5, p6, material));

			//back side triangles
			cube.Children.Add(CreateTriangle(p1, p0, p4, material));
			cube.Children.Add(CreateTriangle(p1, p4, p5, material));

			//left side triangles
			cube.Children.Add(CreateTriangle(p0, p3, p7, material));
			cube.Children.Add(CreateTriangle(p0, p7, p4, material));

			//top side triangles
			cube.Children.Add(CreateTriangle(p7, p6, p5, material));
			cube.Children.Add(CreateTriangle(p7, p5, p4, material));

			//bottom side triangles
			cube.Children.Add(CreateTriangle(p2, p3, p0, material));
			cube.Children.Add(CreateTriangle(p2, p0, p1, material));

			ModelVisual3D model = new ModelVisual3D();
			model.Content = cube;

			Visual3D current = this.mainViewport.Children[0];
			this.mainViewport.Children.Clear();
			this.mainViewport.Children.Add(current);
			this.mainViewport.Children.Add(model);
		}


		private Model3DGroup CreateTriangle(Point3D p0, Point3D p1, Point3D p2, Material material)
		{
			MeshGeometry3D mesh = new MeshGeometry3D();

			mesh.Positions.Add(p0);
			mesh.Positions.Add(p1);
			mesh.Positions.Add(p2);

			mesh.TriangleIndices.Add(0);
			mesh.TriangleIndices.Add(1);
			mesh.TriangleIndices.Add(2);

			Vector3D normal = ComputeNormal(p0, p1, p2);
			mesh.Normals.Add(normal);
			mesh.Normals.Add(normal);
			mesh.Normals.Add(normal);

			GeometryModel3D model = new GeometryModel3D(mesh, material);

			Model3DGroup group = new Model3DGroup();
			group.Children.Add(model);

			return group;
		}

		private Vector3D ComputeNormal(Point3D p0, Point3D p1, Point3D p2)
		{
			Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
			Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
			return Vector3D.CrossProduct(v0, v1);
		}

		private void OnViewportMouseUp(object sender, MouseButtonEventArgs e)
		{
			Mouse.Capture(e.MouseDevice.Target, CaptureMode.None);
		}

		private void OnViewportMouseDown(object sender, MouseButtonEventArgs e)
		{
			Mouse.Capture(e.MouseDevice.Target, CaptureMode.Element);
		}

		private void OnViewportMouseMove(object sender, MouseEventArgs e)
		{
			m_CameraController.Update(e);
		}
	}
}
